#ifndef CUBE_COMMON_DISCOVERY_H
#define CUBE_COMMON_DISCOVERY_H
//-----------------------------------------------------------------
#include "common_coord.h"
//-----------------------------------------------------------------
// discovery service name
//-----------------------------------------------------------------
#define CUBE_SERVICE_DISCOVERY "cube.service.discovery"
//-----------------------------------------------------------------
// parameters for discovery service
//-----------------------------------------------------------------
#define CUBE_DISCOVERY_ACTION "cube.discovery.action"
#define CUBE_DISCOVERY_REGISTRY "cube.discovery.registry"
#define CUBE_DISCOVERY_DISCOVERY "cube.discovery.discovery"
#define CUBE_DISCOVERY_COUNT "cube.discovery.count"
//-----------------------------------------------------------------
// common classes for discovery
//-----------------------------------------------------------------
#include <iostream>
#include "service/CService.h"
//-----------------------------------------------------------------
using namespace std;
//-----------------------------------------------------------------
class CServiceInfo : public CService
{
private:
	string ip;
	int port;

	// status
	float cpu;
	float load;

protected:
	// comparison
	bool CServiceInfo::blindlyEquals(const CObject *rhs) const
	{
#ifdef DEBUG
		cout << "[CServiceInfo] blindlyEquals" << endl;
#endif
		const CServiceInfo *casted_rhs = dynamic_cast<const CServiceInfo *>(rhs);
		if(casted_rhs==NULL) {
#ifdef DEBUG
		cout << "[CServiceInfo] ==================================" << endl;
		cout << "[CServiceInfo] type is not casted" << endl;
#endif

			return false;
		}

		string rhs_name = casted_rhs->getName();
		string rhs_ip = casted_rhs->getIP();
		int rhs_port = casted_rhs->getPort();

		// perform compariosn on private data
#ifdef DEBUG
		cout << "[CServiceInfo] lhs = [" << getName() << "], rhs = [" << rhs_name << "]" << endl;
		cout << "[CServiceInfo] lhs = [" << getIP() << "], rhs = [" << rhs_ip << "]" << endl;
		cout << "[CServiceInfo] lhs = [" << getPort() << "], rhs = [" << rhs_port << "]" << endl;
#endif
		bool isEqual = false;

		if(getName()==rhs_name) {
			if(getName()==NULL||getPort()<0) isEqual = true;
			else if(getIP()==rhs_ip&&getPort()==rhs_port) isEqual = true;
		}
#ifdef DEBUG
		else { cout << "not equals : " << getName()<< " != " << rhs_name<< endl; }

		cout << "===========================" << endl;
		cout << "equal = " << isEqual << endl;
		cout << "===========================" << endl;
#endif

		return (isEqual&&CObject::blindlyEquals(rhs));
	}

	// comparison
	const type_info *CServiceInfo::getTypeEquiv() const
	{
#ifdef DEBUG
		cout << "[CServiceInfo] getTypeEquiv" << endl;
		cout << "[CServiceInfo] typeid name = " << typeid(this).name() << endl;
#endif

		return &typeid(this);
	}

public:
	CServiceInfo() : CService("") {
		setIP("");
		setPort(-1);
		setTTL(MAX_TTL);
		setCPU(0);
		setLoad(0);
	};
	CServiceInfo(char *name, char *ip, int port) : CService(name) {
		if(ip!=NULL) setIP(ip);
		else this->ip = "";
		setPort(port);
		setTTL(MAX_TTL);
		setCPU(0);
		setLoad(0);
	};
	CServiceInfo(char *name, char *ip, int port, time_t ttl) : CService(name) {
		if(ip!=NULL) setIP(ip);
		else this->ip = "";
		setPort(port);
		setTTL(ttl);
		setCPU(0);
		setLoad(0);
	};
	CServiceInfo(const CServiceInfo &rhs) {
		this->setName(rhs.getName());
		this->setIP(rhs.getIP());
		this->setPort(rhs.getPort());
		this->setTTL(rhs.getTTL());
		this->setCPU(rhs.getCPU());
		this->setLoad(rhs.getLoad());
	};
	virtual ~CServiceInfo() {
	};

	CServiceInfo *clone() const {
		return new CServiceInfo(*this);
	};
	CServiceInfo &operator=(const CServiceInfo &rhs) {
		setName(rhs.getName());
		setIP(rhs.getIP());
		setPort(rhs.getPort());
		setTTL(rhs.getTTL());
		setCPU(rhs.getCPU());
		setLoad(rhs.getLoad());

		return *this;
	};

	friend bool operator<(const CServiceInfo &lhs, const CServiceInfo &rhs) {
		int cmp = strcmp(lhs.getIP(), rhs.getIP());
		if(cmp>0) return false;
		else if(cmp<0) return true;
		else {
			return lhs.getPort() < rhs.getPort();
		}
	};

	void set(char *name, char *ip, int port, time_t ttl) {
		setName(name);
		setIP(ip);
		setPort(port);
		setTTL(ttl);
	};
	void setStatus(float cpu, float load) {
		setCPU(cpu);
		setLoad(load);
	};
	void setIP(char *ip) {
		if(ip!=NULL) this->ip = ip;
		else this->ip = "";
	};
	void setPort(int port) {
		this->port = port;
	};
	void setCPU(float cpu) {
		this->cpu = cpu;
	};
	void setLoad(float load) {
		this->load= load;
	};
	char *getIP() const{
		return (char *)this->ip.c_str();
	};
	int getPort() const {
		return this->port;
	};
	float getCPU() const {
		return this->cpu;
	};
	float getLoad() const {
		return this->load;
	};
};
//-----------------------------------------------------------------
#endif
